#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Markdown到HTML转换器

功能：
- 将单个或多个Markdown文件转换为HTML
- 支持CommonMark和GitHub Flavored Markdown语法
- 代码语法高亮
- 自动生成目录
- 响应式设计
- 自定义样式支持
- 批量处理功能
"""

import os
import re
import sys
import argparse
from datetime import datetime
import markdown
from markdown.extensions import toc, codehilite, fenced_code, tables, admonition, nl2br


def read_markdown_file(file_path):
    """读取Markdown文件内容"""
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            return f.read()
    except Exception as e:
        print(f"错误：无法读取文件 {file_path} - {str(e)}")
        return None


def extract_title(markdown_content):
    """从Markdown内容中提取标题"""
    match = re.search(r'^#\s+(.+)$', markdown_content, re.MULTILINE)
    if match:
        return match.group(1)
    return "文档"


def generate_html(markdown_content, title, css_file=None, 
                 enable_toc=True, highlight_theme='default'):
    """将Markdown内容转换为HTML"""
    # 配置Markdown扩展
    extensions = [
        'markdown.extensions.extra',      # 包含表格、fenced_code等
        'markdown.extensions.sane_lists',  # 更合理的列表处理
        'markdown.extensions.smarty',      # 智能引号
        'markdown.extensions.attr_list',   # 支持HTML属性
        'markdown.extensions.md_in_html',  # 在HTML中嵌入Markdown
    ]
    
    # 扩展配置
    extension_configs = {
        'markdown.extensions.codehilite': {
            'css_class': 'highlight',
            'pygments_style': highlight_theme,
            'noclasses': False,
        }
    }
    
    # 添加目录扩展（如果启用）
    if enable_toc:
        extensions.append('markdown.extensions.toc')
        extension_configs['markdown.extensions.toc'] = {
            'title': '目录',
            'toc_depth': '1-6',
            'permalink': False,
        }
    
    # 创建Markdown实例并转换
    md = markdown.Markdown(extensions=extensions, extension_configs=extension_configs)
    html_content = md.convert(markdown_content)
    
    # 获取目录HTML（如果启用）
    toc_html = md.toc if enable_toc else ''
    
    # 生成完整的HTML文档
    html_template = f'''
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{title}</title>
    <meta name="description" content="{title} - 转换自Markdown文档">
    <meta name="generator" content="Markdown to HTML Converter">
    <meta name="author" content="Auto-generated">
    
    <!-- KaTeX支持（可选） -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/katex.min.css">
    <script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/katex.min.js"></script>
    <script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/contrib/auto-render.min.js"></script>
    
    <!-- 代码高亮样式 -->
    <style>
        /* 基础样式 */
        :root {
            --main-text-color: #333333;
            --heading-color: #2c3e50;
            --background-color: #ffffff;
            --paper-color: #ffffff;
            --accent-color: #3498db;
            --border-color: #e0e0e0;
            --code-bg: #f8f8f8;
            --table-header-bg: #f2f2f2;
        }
        
        @media (prefers-color-scheme: dark) {
            :root {
                --main-text-color: #e0e0e0;
                --heading-color: #ecf0f1;
                --background-color: #1a1a1a;
                --paper-color: #2d2d2d;
                --accent-color: #5dade2;
                --border-color: #404040;
                --code-bg: #3d3d3d;
                --table-header-bg: #3a3a3a;
            }
        }
        
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 
                        'Helvetica Neue', Arial, sans-serif;
            font-size: 16px;
            line-height: 1.6;
            color: var(--main-text-color);
            background-color: var(--background-color);
            padding: 0;
            margin: 0;
        }
        
        .container {
            max-width: 1000px;
            margin: 0 auto;
            padding: 20px;
        }
        
        .paper {
            background-color: var(--paper-color);
            padding: 40px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin-bottom: 30px;
        }
        
        /* 标题样式 */
        h1, h2, h3, h4, h5, h6 {
            color: var(--heading-color);
            margin-top: 1.5em;
            margin-bottom: 0.8em;
            font-weight: 600;
            line-height: 1.3;
        }
        
        h1 {
            font-size: 2.2em;
            border-bottom: 2px solid var(--accent-color);
            padding-bottom: 0.3em;
            margin-top: 0;
        }
        
        h2 {
            font-size: 1.8em;
            border-bottom: 1px solid var(--border-color);
            padding-bottom: 0.3em;
        }
        
        h3 {
            font-size: 1.5em;
        }
        
        h4 {
            font-size: 1.2em;
        }
        
        /* 段落样式 */
        p {
            margin-bottom: 1em;
            text-align: justify;
            text-indent: 2em;
        }
        
        /* 链接样式 */
        a {
            color: var(--accent-color);
            text-decoration: none;
            transition: color 0.3s ease;
        }
        
        a:hover {
            color: #2980b9;
            text-decoration: underline;
        }
        
        /* 列表样式 */
        ul, ol {
            margin-bottom: 1em;
            margin-left: 2em;
        }
        
        li {
            margin-bottom: 0.5em;
        }
        
        /* 代码样式 */
        pre, code {
            font-family: 'Courier New', Courier, monospace;
            background-color: var(--code-bg);
            border-radius: 4px;
        }
        
        code {
            padding: 0.2em 0.4em;
            font-size: 0.9em;
        }
        
        pre {
            padding: 1em;
            overflow-x: auto;
            border-radius: 4px;
            margin-bottom: 1em;
        }
        
        pre code {
            padding: 0;
            background-color: transparent;
        }
        
        /* 表格样式 */
        table {
            width: 100%;
            border-collapse: collapse;
            margin-bottom: 1.5em;
            overflow-x: auto;
            display: block;
        }
        
        th, td {
            padding: 10px 12px;
            border: 1px solid var(--border-color);
            text-align: left;
        }
        
        th {
            background-color: var(--table-header-bg);
            font-weight: 600;
        }
        
        tr:nth-child(even) {
            background-color: rgba(0, 0, 0, 0.02);
        }
        
        /* 引用样式 */
        blockquote {
            border-left: 4px solid var(--accent-color);
            padding-left: 1em;
            margin-left: 0;
            margin-right: 0;
            margin-bottom: 1em;
            color: #666;
            font-style: italic;
        }
        
        /* 水平线样式 */
        hr {
            border: none;
            border-top: 1px solid var(--border-color);
            margin: 2em 0;
        }
        
        /* 图片样式 */
        img {
            max-width: 100%;
            height: auto;
            display: block;
            margin: 1em auto;
            border-radius: 4px;
        }
        
        /* 目录样式 */
        .toc {
            background-color: rgba(0, 0, 0, 0.02);
            padding: 1.5em;
            border-radius: 4px;
            margin-bottom: 2em;
        }
        
        .toc h2 {
            margin-top: 0;
            border-bottom: none;
            font-size: 1.3em;
        }
        
        .toc ul {
            list-style-type: none;
            margin-left: 0;
        }
        
        .toc ul ul {
            margin-left: 1.5em;
        }
        
        .toc li {
            margin-bottom: 0.5em;
        }
        
        /* 响应式设计 */
        @media (max-width: 768px) {
            .container {
                padding: 10px;
            }
            
            .paper {
                padding: 20px;
            }
            
            h1 {
                font-size: 1.8em;
            }
            
            h2 {
                font-size: 1.5em;
            }
            
            h3 {
                font-size: 1.3em;
            }
        }
        
        /* 打印样式 */
        @media print {
            body {
                background-color: white;
            }
            
            .container {
                max-width: 100%;
            }
            
            .paper {
                box-shadow: none;
                padding: 0;
            }
        }
        
        /* 进度指示器样式 */
        .progress-container {
            position: fixed;
            top: 0;
            width: 100%;
            height: 4px;
            background: transparent;
            z-index: 1000;
        }
        
        .progress-bar {
            height: 4px;
            background: var(--accent-color);
            width: 0%;
        }
        
        /* 滚动到顶部按钮 */
        .scroll-top {
            position: fixed;
            bottom: 20px;
            right: 20px;
            background-color: var(--accent-color);
            color: white;
            border: none;
            border-radius: 50%;
            width: 40px;
            height: 40px;
            text-align: center;
            font-size: 16px;
            cursor: pointer;
            opacity: 0;
            transition: opacity 0.3s;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
        }
        
        .scroll-top.visible {
            opacity: 1;
        }
        
        .scroll-top:hover {
            background-color: #2980b9;
        }
    </style>
    
    <!-- 自定义CSS文件 -->
    {'<link rel="stylesheet" href="' + css_file + '">' if css_file else ''}
</head>
<body>
    <!-- 进度指示器 -->
    <div class="progress-container">
        <div class="progress-bar" id="progressBar"></div>
    </div>
    
    <div class="container">
        <div class="paper">
            {toc_html}
            
            <main>
                {html_content}
            </main>
        </div>
    </div>
    
    <!-- 滚动到顶部按钮 -->
    <button class="scroll-top" id="scrollTopBtn" title="回到顶部">↑</button>
    
    <script>
        // 页面滚动进度指示器
        window.onscroll = function() {myFunction()};
        
        function myFunction() {
            var winScroll = document.body.scrollTop || document.documentElement.scrollTop;
            var height = document.documentElement.scrollHeight - document.documentElement.clientHeight;
            var scrolled = (winScroll / height) * 100;
            document.getElementById("progressBar").style.width = scrolled + "%";
            
            // 显示/隐藏回到顶部按钮
            var scrollTopBtn = document.getElementById("scrollTopBtn");
            if (winScroll > 300) {
                scrollTopBtn.classList.add("visible");
            } else {
                scrollTopBtn.classList.remove("visible");
            }
        }
        
        // 回到顶部功能
        document.getElementById("scrollTopBtn").addEventListener("click", function() {
            window.scrollTo({top: 0, behavior: 'smooth'});
        });
        
        // 平滑滚动到锚点
        document.querySelectorAll('a[href^="#"]').forEach(anchor => {
            anchor.addEventListener('click', function (e) {
                e.preventDefault();
                const targetId = this.getAttribute('href');
                const targetElement = document.querySelector(targetId);
                if (targetElement) {
                    targetElement.scrollIntoView({ 
                        behavior: 'smooth' 
                    });
                }
            });
        });
        
        // 渲染数学公式（如果KaTeX已加载）
        document.addEventListener("DOMContentLoaded", function() {
            if (typeof renderMathInElement !== 'undefined') {
                renderMathInElement(document.body, {
                    delimiters: [
                        {left: "$$", right: "$$", display: true},
                        {left: "$", right: "$", display: false}
                    ]
                });
            }
        });
        
        // 图片懒加载
        document.addEventListener("DOMContentLoaded", function() {
            const images = document.querySelectorAll("img");
            
            const imgOptions = {
                threshold: 0,
                rootMargin: "0px 0px 300px 0px"
            };
            
            const imgObserver = new IntersectionObserver((entries, observer) => {
                entries.forEach(entry => {
                    if (!entry.isIntersecting) return;
                    
                    const img = entry.target;
                    const src = img.getAttribute("src");
                    
                    if (src) {
                        img.classList.add("loaded");
                    }
                    
                    observer.unobserve(img);
                });
            }, imgOptions);
            
            images.forEach(image => {
                imgObserver.observe(image);
            });
        });
    </script>
</body>
</html>
'''
    
    return html_template


def write_html_file(html_content, output_path):
    """将HTML内容写入文件"""
    try:
        # 确保输出目录存在
        os.makedirs(os.path.dirname(output_path), exist_ok=True)
        
        with open(output_path, 'w', encoding='utf-8') as f:
            f.write(html_content)
        return True
    except Exception as e:
        print(f"错误：无法写入文件 {output_path} - {str(e)}")
        return False


def convert_single_file(input_file, output_file=None, css_file=None, 
                       enable_toc=True, highlight_theme='default'):
    """转换单个Markdown文件"""
    print(f"正在处理文件: {input_file}")
    
    # 读取Markdown内容
    markdown_content = read_markdown_file(input_file)
    if not markdown_content:
        return False
    
    # 提取标题
    title = extract_title(markdown_content)
    
    # 生成HTML内容
    html_content = generate_html(markdown_content, title, css_file, enable_toc, highlight_theme)
    
    # 确定输出文件路径
    if not output_file:
        base_name = os.path.splitext(os.path.basename(input_file))[0]
        output_file = os.path.join(os.path.dirname(input_file), f"{base_name}.html")
    
    # 写入HTML文件
    success = write_html_file(html_content, output_file)
    
    if success:
        print(f"转换成功！HTML文件已保存至: {output_file}")
    
    return success


def convert_directory(input_dir, output_dir=None, css_file=None, 
                      enable_toc=True, highlight_theme='default'):
    """批量转换目录中的Markdown文件"""
    # 确定输出目录
    if not output_dir:
        output_dir = input_dir
    
    # 创建输出目录（如果不存在）
    os.makedirs(output_dir, exist_ok=True)
    
    # 统计信息
    total_files = 0
    successful_conversions = 0
    failed_conversions = 0
    failed_files = []
    
    # 遍历目录
    print(f"正在扫描目录: {input_dir}")
    for root, _, files in os.walk(input_dir):
        for file in files:
            if file.endswith(('.md', '.markdown', '.MD', '.MARKDOWN')):
                total_files += 1
                input_file = os.path.join(root, file)
                
                # 确定输出文件路径（保持目录结构）
                rel_path = os.path.relpath(root, input_dir)
                file_output_dir = os.path.join(output_dir, rel_path)
                base_name = os.path.splitext(file)[0]
                output_file = os.path.join(file_output_dir, f"{base_name}.html")
                
                # 转换文件
                success = convert_single_file(input_file, output_file, css_file, enable_toc, highlight_theme)
                
                if success:
                    successful_conversions += 1
                else:
                    failed_conversions += 1
                    failed_files.append(input_file)
    
    # 打印统计信息
    print(f"\n转换完成！")
    print(f"总计: {total_files} 个文件")
    print(f"成功: {successful_conversions} 个文件")
    print(f"失败: {failed_conversions} 个文件")
    
    if failed_files:
        print("\n失败的文件:")
        for file in failed_files:
            print(f"  - {file}")
    
    return successful_conversions > 0


def create_default_css(output_path):
    """创建默认CSS文件"""
    css_content = '''
/* 自定义CSS样式 - Markdown转HTML */

/* 基本样式重写 */
body {
    font-family: 'Microsoft YaHei', sans-serif;
    background-color: #f5f5f5;
}

.paper {
    background-color: #ffffff;
    max-width: 900px;
    margin: 30px auto;
    padding: 40px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
    border-radius: 8px;
}

/* 标题样式 */
h1 {
    color: #1a237e;
    border-bottom: 3px solid #3f51b5;
    padding-bottom: 10px;
}

h2 {
    color: #303f9f;
    border-bottom: 2px solid #c5cae9;
}

h3, h4, h5, h6 {
    color: #3949ab;
}

/* 链接样式 */
a {
    color: #303f9f;
    text-decoration: none;
    border-bottom: 1px dotted #303f9f;
}

a:hover {
    color: #3f51b5;
    border-bottom: 1px solid #3f51b5;
}

/* 表格样式 */
table {
    border-collapse: collapse;
    width: 100%;
    margin: 20px 0;
}

th, td {
    padding: 12px 15px;
    text-align: left;
    border-bottom: 1px solid #ddd;
}

th {
    background-color: #e8eaf6;
    color: #303f9f;
    font-weight: bold;
}

tr:hover {
    background-color: #f5f5f5;
}

/* 引用样式 */
blockquote {
    background-color: #f5f5f5;
    border-left: 4px solid #3f51b5;
    padding: 15px;
    margin: 20px 0;
    font-style: italic;
}

/* 代码块样式 */
pre {
    background-color: #f8f8f8;
    border: 1px solid #e0e0e0;
    border-radius: 4px;
    padding: 15px;
    overflow-x: auto;
}

code {
    font-family: 'Courier New', monospace;
    background-color: #f8f8f8;
    padding: 2px 4px;
    border-radius: 3px;
}

/* 目录样式 */
.toc {
    background-color: #f5f7fa;
    border: 1px solid #e0e0e0;
    border-radius: 4px;
    padding: 20px;
    margin-bottom: 30px;
}

.toc h2 {
    margin-top: 0;
    border-bottom: none;
}

.toc ul {
    list-style-type: none;
    padding-left: 20px;
}

.toc li {
    margin-bottom: 8px;
}

/* 响应式设计 */
@media (max-width: 768px) {
    .paper {
        padding: 20px;
        margin: 10px;
    }
    
    table {
        font-size: 14px;
    }
    
    th, td {
        padding: 8px;
    }
}
    '''
    
    try:
        with open(output_path, 'w', encoding='utf-8') as f:
            f.write(css_content)
        print(f"默认CSS文件已创建: {output_path}")
        return True
    except Exception as e:
        print(f"创建默认CSS文件失败: {str(e)}")
        return False


def main():
    """主函数"""
    # 解析命令行参数
    parser = argparse.ArgumentParser(description='将Markdown文件转换为HTML')
    parser.add_argument('input', help='输入文件或目录路径')
    parser.add_argument('-o', '--output', help='输出文件或目录路径')
    parser.add_argument('-c', '--css', help='自定义CSS文件路径')
    parser.add_argument('--no-toc', action='store_true', help='禁用目录生成')
    parser.add_argument('--theme', default='default', help='代码高亮主题（默认: default）')
    parser.add_argument('--create-css', action='store_true', help='创建默认CSS文件')
    
    args = parser.parse_args()
    
    # 创建默认CSS文件（如果请求）
    if args.create_css:
        css_path = args.css or 'default_style.css'
        create_default_css(css_path)
        return
    
    # 检查输入路径是否存在
    if not os.path.exists(args.input):
        print(f"错误：输入路径 '{args.input}' 不存在")
        return
    
    # 处理单个文件
    if os.path.isfile(args.input):
        if not args.input.endswith(('.md', '.markdown', '.MD', '.MARKDOWN')):
            print(f"警告：输入文件 '{args.input}' 可能不是Markdown文件")
        
        convert_single_file(
            args.input,
            args.output,
            args.css,
            not args.no_toc,
            args.theme
        )
    # 处理目录
    elif os.path.isdir(args.input):
        convert_directory(
            args.input,
            args.output,
            args.css,
            not args.no_toc,
            args.theme
        )


if __name__ == '__main__':
    main()
